package com.pic.mgt.syushin.executer.tar;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.GZIPOutputStream;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.utils.IOUtils;

public final class SyushinTarFileService implements TarFile {
	private boolean usingGZipCompress = false;
	private boolean isInterruptTarAction = false;
	private boolean taring = false;
	private TarFileListener tarFileListener;

	@Override
	public File tarFile(List<File> sourceFileList,
						String destDir,
						String destTarFilenameStr)
						throws TarFileException {
			
		if (null == sourceFileList || null == destDir || null == destTarFilenameStr) {
			throw new TarFileException("Didn't provide source file list ,dest dir or tar filename.");
		}
		
		// 設定開始處理 tar檔動作 旗標
		taring = true;
		
		// 設定tar檔過程中是否中斷執行的旗標
		isInterruptTarAction = false;
		
		File tarFile = new File(destDir, destTarFilenameStr);
		
		OutputStream tarFileOutputStream = null;
		TarArchiveOutputStream tarArchiveOutputStream = null;
		InputStream sourceFileInputStream = null;
		try {
			tarFileOutputStream = new FileOutputStream(tarFile);
			if (this.usingGZipCompress) {
				tarFileOutputStream = new GZIPOutputStream(tarFileOutputStream);
			}
			
			tarArchiveOutputStream = new TarArchiveOutputStream(tarFileOutputStream);
			for (File sourceFile : sourceFileList) {
				if (this.isInterruptTarAction) {
            		throw new TarFileException("Taring file '" + tarFile.getAbsolutePath()
							+ "' process has been interrupted.");
            	}
				
				tarArchiveOutputStream.putArchiveEntry(new TarArchiveEntry(sourceFile, sourceFile.getName()));
				sourceFileInputStream = new FileInputStream(sourceFile);
				
				IOUtils.copy(sourceFileInputStream, tarArchiveOutputStream);
				
				sourceFileInputStream.close();
				tarArchiveOutputStream.closeArchiveEntry();
				
				// 通知該 source 檔處理完成(加入 tar 檔中)
				if (null != this.tarFileListener) {
					this.tarFileListener.processedAnEntryNotify(sourceFile, tarFile);
				}
			}
			
			tarArchiveOutputStream.finish();
			tarArchiveOutputStream.close();
			
			tarArchiveOutputStream = null;
			tarFileOutputStream = null;
			sourceFileInputStream = null;
		} catch (IOException e) {
			throw new TarFileException(
					"Taring file '" + tarFile + "' failed.  Occured an I/O error.", e);
		} finally {
			if (null != tarArchiveOutputStream) {
				org.apache.commons.io.IOUtils.closeQuietly(tarArchiveOutputStream);
			}
			
			if (null != tarFileOutputStream) {
				org.apache.commons.io.IOUtils.closeQuietly(tarFileOutputStream);
			}
			
			if (null != sourceFileInputStream) {
				org.apache.commons.io.IOUtils.closeQuietly(sourceFileInputStream);
			}
			
			taring = false;
		}
		
		return tarFile;
	}
	
	@Override
	public boolean isUsingGZipCompress() {
		return this.usingGZipCompress;
	}

	@Override
	public void setGZipCompress(boolean status) {
		if (!this.taring) {
			this.usingGZipCompress = status;
		}
	}
	
	@Override
	public void interruptDeTarAction() {
		this.isInterruptTarAction = true;
	}
	
	@Override
	public TarFileListener getTarFileListener() {
		return this.tarFileListener;
	}
	
	@Override
	public void setTarFileListener(TarFileListener tarFileListener) {
		if (!this.taring) {
			this.tarFileListener = tarFileListener;
		}
	}
}
